package com.hup.minicontroller.client.service;

import android.os.Build;
import android.os.Handler;
import android.util.Log;

import com.hup.minicontroller.client.ClientApplication;
import com.hup.minicontroller.client.model.AppState;
import com.hup.minicontroller.client.mvp.IClientHandler;
import com.hup.minicontroller.client.mvp.IMainView;
import com.hup.minicontroller.common.bluetooth.BluetoothClient;
import com.hup.minicontroller.common.bluetooth.BluetoothClient.BtClientCallback;
import com.hup.minicontroller.common.bluetooth.BluetoothClient.BtClientConfig;
import com.hup.minicontroller.common.bluetooth.BluetoothClient.ConnectState;
import com.hup.minicontroller.common.bluetooth.framework.BtChannel;
import com.hup.minicontroller.common.bluetooth.handler.BtDataSplitCodecHandler;
import com.hup.minicontroller.common.bluetooth.handler.BtHeartbeatHandler;
import com.hup.minicontroller.common.bluetooth.handler.BtHeartbeatHandler.BtIdleCallback;
import com.hup.minicontroller.common.bluetooth.handler.BtLoginResponseHandler.BtLoginResponseCallback;
import com.hup.minicontroller.common.bluetooth.handler.dataLIstener.BtNetSpeedListener;
import com.hup.minicontroller.common.bluetooth.model.BtLoginResponsePacket;
import com.hup.minicontroller.common.constant.ControlActionConstant.FunctionButton;
import com.hup.minicontroller.common.constant.NetConstant.ConnectType;
import com.hup.minicontroller.common.framework.SubThreadHandler;
import com.hup.minicontroller.common.model.dto.BtLoginResponse;
import com.hup.minicontroller.common.model.dto.ControlConfigDto;
import com.hup.minicontroller.common.model.dto.FullScreenTouchRequest;
import com.hup.minicontroller.common.model.dto.FunctionButtonRequest;
import com.hup.minicontroller.common.model.dto.LoginRequest;
import com.hup.minicontroller.common.model.dto.LoginResponse;
import com.hup.minicontroller.common.model.dto.TouchPadTouchRequest;
import com.hup.minicontroller.common.netty.model.LoginResponsePacket;

import java.util.Locale;

import lombok.Getter;

/**
 * 蓝牙client
 */
public class BluetoothClientService implements IClientHandler {
    private static final String TAG = BluetoothClientService.class.getSimpleName();

    private final AppState appState;
    private final BtClientConfig clientConfig;
    private final BluetoothClient client;
    private final BtNetSpeedListener netSpeedListener;

    @Getter
    private ConnectType connectType = ConnectType.BLUETOOTH;

    BluetoothClientService(DataHandlerService dataHandlerService) {
        appState = ClientApplication.getBean(MainService.class).getAppState();
        MyClientCallback clientCallback = new MyClientCallback();
        clientConfig = new BtClientConfig(appState.getAppConfig().getBtUuid(), clientCallback);
        clientConfig.setLoginResponseCallback(clientCallback);
        clientConfig.setIdleCallback(clientCallback);
        clientConfig.addDataHandler(dataHandlerService);
        client = new BluetoothClient(clientConfig);
        netSpeedListener = new BtNetSpeedListener();
        BtDataSplitCodecHandler.INSTANCE.addDataListener(netSpeedListener);
        //BtDataSplitCodecHandler.INSTANCE.addDataListener(new BtPrintDataListener());//测试时打印数据
    }

    @Override
    public void switchClient(boolean isConnect) {
        Log.i(TAG, "switchClient: " + isConnect);
        if (isConnect) {
            clientConfig.setTargetServer(appState.getAppConfig().getBluetoothServer());
            client.connect();
        } else {
            client.disconnect();
        }
    }

    @Override
    public void onControlConfigChanged() {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        Log.i(TAG, "onControlConfigChanged: ");
        client.send(appState.getControlConfig());
    }

    @Override
    public void onFunctionButton(FunctionButton button) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        Log.i(TAG, "onFunctionButton: " + button.desc);
        client.send(new FunctionButtonRequest(button.index));
    }

    @Override
    public void onFullScreenTouch(FullScreenTouchRequest fullScreenTouch) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        //Log.i(TAG, "onFullScreenTouch: ");
        client.send(fullScreenTouch);
    }

    @Override
    public void onTouchPadTouch(TouchPadTouchRequest touchPadTouch) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        //Log.i(TAG, "touchPadTouch: ");
        client.send(touchPadTouch);
    }

    @Override
    public void doTerminate() {
        Log.i(TAG, "doTerminate: ");
        client.doTerminate();
    }

    @Override
    public void getSpeedText(StringBuilder sb) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        netSpeedListener.updateSpeed();
        sb.append(String.format(Locale.getDefault(), "蓝牙  发送: %dKB/s, 接收: %dKB/s", netSpeedListener.getSendSpeed(), netSpeedListener.getReceiveSpeed()));
    }

    private class MyClientCallback implements BtClientCallback, BtLoginResponseCallback<LoginRequest, BtLoginResponse>, BtIdleCallback {

        /**
         * LoginResponse转化;
         * 与LoginRequest不一样, LoginResponse有failure方法,需要被实例化,所以不能定义成接口,所以只能有两个相同的类LoginResponse;
         */
        private LoginResponsePacket caseTo(BtLoginResponsePacket loginResponse) {
            LoginResponsePacket res = new LoginResponse();
            res.setSuccess(loginResponse.isSuccess());
            res.setErrorMessage(loginResponse.getErrorMessage());
            return res;
        }

        @Override
        public void onConnectResult(boolean success, BtLoginResponsePacket loginResponse) {
            Log.i(TAG, "onConnectResult: " + success + ", loginResponse=" + loginResponse);
            if (success) {
                BtLoginResponse response = (BtLoginResponse) loginResponse;
                appState.setConnectedType(getConnectType());
                appState.setServerName(response.getServerName());
                ControlConfigDto controlConfig = response.getControlConfig();
                if (controlConfig != null) appState.getControlConfig().apply(controlConfig);
            } else {
                appState.onDisconnect();
            }
            ClientApplication.executeIfExist(IMainView.class, iMainView -> iMainView.onConnectResult(caseTo(loginResponse)));
        }

        @Override
        public void onConnectionLost() {
            Log.i(TAG, "onConnectionLost: ");
            appState.onDisconnect();
            ClientApplication.executeIfExist(IMainView.class, IMainView::onConnectionLost);
            ClientApplication.executeIfExist(LanBroadcastReceiverService.class, s -> s.switchService(true));
            ClientApplication.executeIfExist(BluetoothDeviceService.class, s -> s.switchService(true));
        }

        @Override
        public Handler getHandler() {
            return ClientApplication.getBean(SubThreadHandler.class);
        }

        @Override
        public Class<BtLoginResponse> getLoginResponseType() {
            return BtLoginResponse.class;
        }

        @Override
        public LoginRequest getLoginValidData() {
            LoginRequest loginRequest = new LoginRequest();
            loginRequest.setName(Build.MODEL);
            Log.i(TAG, "getLoginValidData: " + loginRequest);
            return loginRequest;
        }

        @Override
        public void onChannelIdle(BtChannel btChannel) {
            Log.i(TAG, "onChannelIdle: 无收到消息=" + BtHeartbeatHandler.getReaderIdleTime() + "秒,主动关闭连接");
            btChannel.disconnect();
            ClientApplication.executeIfExist(IMainView.class, IMainView::onChannelIdle);
        }
    }

}
